"""
带额外状态信息的回调函数

问题：
    你的代码中需要依赖到回调函数的使用(比如事件处理器、等待后台任务完成后的回调等)，
    并且你还需要让回调函数拥有额外的状态值，以便在它的内部使用到。
解决方案：
    这一小节主要讨论的是那些出现在很多函数库和框架中的回调函数的使用——特别是跟异步处理有关的。
"""


def apply_async(func, args, *, callback):
    result = func(*args)

    # 回调
    callback(result)


def print_result(result):
    print(result)


def show(book, content):
    return book, content


class ResultHandler:
    def __init__(self):
        self.sequence = 0

    def handler(self, result):
        self.sequence += 1
        print("[{}] Got: {}".format(self.sequence, result))


def use_callback_way1():
    """
    使用类的方式
    """

    result = ResultHandler()
    apply_async(show, ("米开朗琪罗", "真正的英雄主义是认清生活真相后还得依然热爱它"), callback=result.handler)
    apply_async(show, ("米开朗琪罗", "真正的英雄主义是认清生活真相后还得依然热爱它"), callback=result.handler)
    # 输出结果：
    """
    [1] Got: ('米开朗琪罗', '真正的英雄主义是认清生活真相后还得依然热爱它')
    [2] Got: ('米开朗琪罗', '真正的英雄主义是认清生活真相后还得依然热爱它')
    """


def make_handler():
    sequence = 0

    def handler(result):
        nonlocal sequence
        sequence += 1
        print("[{}] Got: {}".format(sequence, result))

    return handler


def use_callback_way2():
    """
    使用闭包的方式
    """

    handler = make_handler()
    apply_async(show, ("米开朗琪罗", "真正的英雄主义是认清生活真相后还得依然热爱它"), callback=handler)
    apply_async(show, ("米开朗琪罗", "真正的英雄主义是认清生活真相后还得依然热爱它"), callback=handler)
    # 输出结果：
    """
    [1] Got: ('米开朗琪罗', '真正的英雄主义是认清生活真相后还得依然热爱它')
    [2] Got: ('米开朗琪罗', '真正的英雄主义是认清生活真相后还得依然热爱它')
    """


def make_hanlder_coroutine():
    sequence = 0
    while True:
        result = yield
        sequence += 1
        print("[{}] Got: {}".format(sequence, result))


def use_callback_way3():
    """
    使用协程的方式
    """

    handler = make_handler()
    apply_async(show, ("米开朗琪罗", "真正的英雄主义是认清生活真相后还得依然热爱它"), callback=handler)
    apply_async(show, ("米开朗琪罗", "真正的英雄主义是认清生活真相后还得依然热爱它"), callback=handler)
    # 输出结果：
    """
    [1] Got: ('米开朗琪罗', '真正的英雄主义是认清生活真相后还得依然热爱它')
    [2] Got: ('米开朗琪罗', '真正的英雄主义是认清生活真相后还得依然热爱它')
    """


if __name__ == '__main__':
    # use_callback_way1()
    # use_callback_way2()
    use_callback_way3()
